# coding=utf-8
# create by oldman at 2017/12/1

"""
Question：
    你想在适用范围内执行某个代码片段，并且希望在执行后所有的结果都不可见
Solution:
    为了理解这个问题，先试试一个简单场景。首先，在全局命名空间内执行一个代码片段：
    >>> a=13
    ... exec('b=1+1')
    ... print(b)
    14
    >>>
    然后再在一个函数中执行同样的代码：
    >>> def test():
    ...     a=13
    ...     exec ('b=1+a')
    ...     print(b)
    >>> test()
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 4, in test
    NameError: global name 'b' is not defined


    可以看出，最后抛出一个NameError异常，就跟在exec() 语句从没执行过一样。
    要是你想在后面的计算中使用到exec()执行结果的话就会有问题了。
    为了修正这样的错误，你需要在调用exec()之前使用locals（）函数来得到一个局部变量字典
    之后你就能从局部字典中获取修改过后的变量值了。例如：
    >>> def test():
    ...     a = 13
    ...     loc = locals()
    ...     exec ('b=a+1')
    ...     b = loc['b']
    ...     print(b)
    >>> test()
    14
    >>>
讨论：
    实际上对于exec()的正确使用是比较难的。大多数情况下当你要考虑使用exec()的时候，
    还有另外更好的解决方案(比如装饰器，闭包，元类等等)。

    然而，如果你仍然要使用exec()，本节列出了一些如何正确使用它的方法。默认情况下，
    exec()会在调用者局部和全局范围内执行代码。然而，在函数里面，传递给exec()的局部范围是
    拷贝实际局部变量组成的一个字典。因此，如果exec()如果执行了修改操作，这种修改后的结果对
    实际局部变量值是没有影响的。下面是另外一个演示它的例子：
    >>> def test():
    ...     x = 0
    ...     exec ('x+=1')
    ...     print(x)
    ...
    >>> test()
    0
    >>>
    上面代码里，当你调用locals()获取局部变量时，你获得的是传递给exec()的局部变量的一个拷贝。
    通过在代码执行后审查这个字典的值，那就能获取修改后的值了。下面是一个演示例子：
    >>> def test3():
    ...     x = 0
    ...     loc = locals()
    ...     print(loc)
    ...     exec('x += 1')
    ...     print(loc)
    ...     locals()
    ...     print(loc)
    ...
    >>> test3()
    {'x': 0}
    {'loc': {...}, 'x': 1}
    {'loc': {...}, 'x': 0}
    >>>
    注意最后一次调用 locals() 的时候x的值是如何被覆盖掉的。

    作为 locals() 的一个替代方案，你可以使用你自己的字典，并将它传递给 exec() 。例如：

    >>> def test4():
    ...     a = 13
    ...     loc = { 'a' : a }
    ...     glb = { }
    ...     exec('b = a + 1', glb, loc)
    ...     b = loc['b']
    ...     print(b)
    ...
    >>> test4()
    14
    >>>
    大部分情况下，这种方式是使用 exec() 的最佳实践。 你只需要保证全局和局部字典在后面代码访问时已经被初始化。

    还有一点，在使用 exec() 之前，你可能需要问下自己是否有其他更好的替代方案。 大多数情况下当你要考虑使用 exec() 的时候， 还有另外更好的解决方案，比如装饰器、闭包、元类，或其他一些元编程特性。

    Next  Previous

"""